﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Windows;
using FBA.Utils;

namespace FBA.Client.Utils
{
    public partial class DataRequest
    {
        private static string BaseUrl
        {
            get
            {
                string value = ConfigurationManager.AppSettings["server.url"];
                if (string.IsNullOrEmpty(value))
                {
                    value = "http://localhost:8280";
                }
                return value;
            }
        }

        public static DataTable Query(string sql, object[] args, DataColumn[] columns, bool strict)
        {
            string dataServiceURL = BaseUrl + "/data";
            HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(dataServiceURL);
            hwr.Accept = "application/json";
            hwr.ContentType = "application/json";
            hwr.Method = "POST";
            hwr.KeepAlive = true;
            hwr.ReadWriteTimeout = 3000;

            SQLQueryObject sqo = new SQLQueryObject() { sql = sql, args = args };
            byte[] data = Encoding.GetEncoding("utf-8").GetBytes(JSON.Serialize(sqo));

            using (Stream stream = hwr.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
                stream.Close();
            }
            Stream stre = hwr.GetResponse().GetResponseStream();
            StreamReader sr = new StreamReader(stre);//创建一个stream读取流
            string result = sr.ReadToEnd();

            DataRequestResult<JSONTable> drr = JSON.Deserialize<DataRequestResult<JSONTable>>(result);
            sr.Close();

            if (drr.Status == DataRequestResult<JSONTable>.SUCCESS)
            {
                DataTable dt = new DataTable();

                JSONTable jt = drr.Data;
                foreach (ColumnMeta cm in jt.ColumnMeta)
                {
                    if (strict == false)
                    {
                        dt.Columns.Add(cm.Name);
                    }
                    else
                    {
                        Type type = null;

                        if (cm.JavaType.Equals("java.lang.Short"))
                        {
                            type = typeof(short);
                        }
                        else if (cm.JavaType.Equals("java.lang.Integer"))
                        {
                            type = typeof(int);
                        }
                        else if (cm.JavaType.Equals("java.lang.Long"))
                        {
                            type = typeof(long);
                        }
                        else if (cm.JavaType.Equals("java.lang.BigDecimal"))
                        {
                            type = typeof(decimal);
                        }
                        else if (cm.JavaType.Equals("java.sql.Timestamp"))
                        {
                            type = typeof(DateTime);
                        }
                        else
                        {
                            type = typeof(string);
                        }
                        dt.Columns.Add(cm.Name, type);
                    }
                }
                if (columns != null && columns.Length > 0)
                {
                    dt.Columns.AddRange(columns);
                }
                object[][] array = jt.Data;
                for (int i = 0; i < array.Length; i++)
                {
                    object[] row = array[i];
                    DataRow dr = dt.NewRow();
                    for (int j = 0; j < row.Length; j++)
                    {
                        if (strict == false)
                        {
                            dr[j] = row[j];
                        }
                        else
                        {
                            dr[j] = Converter.Convert(row[j], dt.Columns[j].DataType);
                        }
                    }
                    dt.Rows.Add(dr);
                }
                return dt;
            }
            else
            {
                throw new Exception(drr.Message);
            }
        }

        public static DataTable Query(string sql, object[] args, DataColumn[] columns)
        {
            return Query(sql, args, columns, false);
        }

        public static DataTable Query(string sql, object[] args, DataColumn column)
        {
            return Query(sql, args, new DataColumn[] { column });
        }

        public static DataTable Query(string sql, object[] args, DataColumn column, bool strict)
        {
            return Query(sql, args, new DataColumn[] { column }, strict);
        }

        public static DataTable Query(string sql, object[] args)
        {
            return Query(sql, args, (DataColumn[])null);
        }

        public static DataTable Query(string sql, object[] args, bool strict)
        {
            return Query(sql, args, (DataColumn[])null, strict);
        }

        public static DataTable Query(string sql, DataColumn[] columns)
        {
            return Query(sql, null, columns);
        }

        public static DataTable Query(string sql, DataColumn[] columns, bool strict)
        {
            return Query(sql, null, columns, strict);
        }

        public static DataTable Query(string sql, DataColumn column)
        {
            return Query(sql, null, new DataColumn[] { column });
        }

        public static DataTable Query(string sql, DataColumn column, bool strict)
        {
            return Query(sql, null, new DataColumn[] { column }, strict);
        }

        public static DataTable Query(string sql)
        {
            return Query(sql, null, (DataColumn[])null);
        }
        public static DataTable Query(string sql, bool strict)
        {
            return Query(sql, null, (DataColumn[])null, strict);
        }

        public static Dictionary<string, object> QueryDictionary(string sql, object[] args, bool forceKey, bool strict)
        {
            DataTable dt = Query(sql, args, strict);
            if (dt.Rows.Count > 0)
            {
                DataRow row = dt.Rows[0];
                Dictionary<string, object> dic = new Dictionary<string, object>();
                foreach (DataColumn col in dt.Columns)
                {
                    dic.Add(col.ColumnName, row[col]);
                }
                return dic;
            }
            else if (dt.Rows.Count == 0 && forceKey == true)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                foreach (DataColumn col in dt.Columns)
                {
                    dic.Add(col.ColumnName, null);
                }
                return dic;
            }
            return null;

        }
        public static Dictionary<string, object> QueryDictionary(string sql, object[] args, bool forceKey)
        {
            return QueryDictionary(sql, args, forceKey, false);
        }


        public static Dictionary<string, object> QueryDictionary(string sql, object[] args)
        {
            return QueryDictionary(sql, args, false);
        }


        public static Dictionary<string, object> QueryDictionary(string sql, bool forceKey)
        {
            return QueryDictionary(sql, null, forceKey);
        }

        public static Dictionary<string, object> QueryDictionary(string sql, bool forceKey, bool strict)
        {
            return QueryDictionary(sql, null, forceKey, strict);
        }

        public static Dictionary<string, object> QueryDictionary(string sql)
        {
            return QueryDictionary(sql, null, false);
        }

        public static T QueryOne<T>(string sql, object[] args = null)
        {
            DataTable dt = Query(sql, args);
            if (dt.Rows.Count > 0)
            {
                DataRow row = dt.Rows[0];
                DataColumnCollection columns = dt.Columns;

                Type type = typeof(T);

                if (type.Equals(typeof(string)) ||
                       type.Equals(typeof(int)) ||
                       type.Equals(typeof(int?)) ||
                       type.Equals(typeof(short)) ||
                       type.Equals(typeof(short?)) ||
                       type.Equals(typeof(long)) ||
                       type.Equals(typeof(long?)) ||
                       type.Equals(typeof(decimal)) ||
                       type.Equals(typeof(decimal?)) ||
                       type.Equals(typeof(bool?)) ||
                       type.Equals(typeof(bool?)))
                {
                    return Converter.Convert(row[0], type);
                }
                else
                {
                    T instance = Activator.CreateInstance<T>(); //新建对象实例 

                    //变量数据源，构造T对象，把数据源的值装入T对象
                    foreach (DataColumn column in columns)
                    {
                        string columnName = column.ColumnName;
                        string propertyName = PropertyUtils.ToCamelCase(column.ColumnName);

                        try
                        {
                            PropertyInfo propertyInfo = type.GetProperty(propertyName);
                            if (propertyInfo != null)
                            {
                                //类型强转，将table字段类型转为集合字段类型  
                                var value = Convert.ChangeType(row[columnName], propertyInfo.PropertyType);
                                propertyInfo.SetValue(instance, value);
                            }
                        }
                        catch (Exception)
                        {
                        }
                    }
                    return instance;
                }
            }
            else
            {
                return default(T);
            }
        }

        public static List<T> QueryList<T>(string sql, object[] args = null)
        {
            string dataServiceURL = BaseUrl + "/data";

            HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(dataServiceURL);
            hwr.Accept = "application/json";
            hwr.ContentType = "application/json";
            hwr.Method = "POST";
            hwr.KeepAlive = true;
            hwr.ReadWriteTimeout = 3000;

            SQLQueryObject sqo = new SQLQueryObject() { sql = sql, args = args };

            byte[] data = Encoding.GetEncoding("utf-8").GetBytes(JSON.Serialize(sqo));

            using (Stream stream = hwr.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
                stream.Close();
            }
            Stream stre = hwr.GetResponse().GetResponseStream();
            StreamReader sr = new StreamReader(stre);//创建一个stream读取流
            string result = sr.ReadToEnd();

            DataRequestResult<JSONTable> drr = JSON.Deserialize<DataRequestResult<JSONTable>>(result);
            sr.Close();

            if (drr.Status == DataRequestResult<JSONTable>.SUCCESS)
            {
                List<T> list = new List<T>();
                JSONTable jt = drr.Data;
                object[][] array = jt.Data;
                for (int i = 0; i < array.Length; i++)
                {
                    object[] row = array[i];
                    Type type = typeof(T);

                    if (type.Equals(typeof(string)) ||
                        type.Equals(typeof(int)) ||
                        type.Equals(typeof(int?)) ||
                        type.Equals(typeof(short)) ||
                        type.Equals(typeof(short?)) ||
                        type.Equals(typeof(long)) ||
                        type.Equals(typeof(long?)) ||
                        type.Equals(typeof(decimal)) ||
                        type.Equals(typeof(decimal?)) ||
                         type.Equals(typeof(bool?)) ||
                        type.Equals(typeof(bool?)))
                    {
                        list.Add(Converter.Convert<T>(row[0]));
                    }
                    else
                    {
                        T instance = Activator.CreateInstance<T>();
                        //循环遍历，取行里面的每个字段，构造成T对象
                        foreach (ColumnMeta cm in jt.ColumnMeta)
                        {
                            string columnName = cm.Name;
                            string propertyName = PropertyUtils.ToCamelCase(columnName);
                            try
                            {
                                PropertyInfo propertyInfo = type.GetProperty(propertyName);
                                if (propertyInfo != null)
                                {
                                    //Idx base 1
                                    var value = Convert.ChangeType(row[cm.Idx - 1], propertyInfo.PropertyType); //类型强转，将table字段类型转为集合字段类型  
                                    propertyInfo.SetValue(instance, value);
                                }
                            }
                            catch (Exception)
                            {
                            }
                        }
                        list.Add(instance);
                    }
                }
                return list;
            }
            else
            {
                throw new Exception(drr.Message);
            }

        }


        public static string Post(string url, string json)
        {

            string result = string.Empty;
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(BaseUrl + url);
            req.Method = "POST";
            req.UserAgent = "JNET/1.0";
            req.ContentType = "application/json";
            req.Headers.Add("x-requested-with", "XMLHttpRequest");
            req.Headers.Add("language", "zh_CN");
            //req.Headers.Add("account", HttpUtility.UrlEncode(LoginWindow.username, Encoding.GetEncoding("UTF-8")));
            //req.Headers.Add("password", HttpUtility.UrlEncode(LoginWindow.password, Encoding.GetEncoding("UTF-8")));
            req.Timeout = 120000;
            req.ProtocolVersion = new Version(1, 1);   //Http/1.1版本
            if (ENV.JSESSION != null)
            {
                req.Headers.Add("Cookie", "JSESSIONID=" + ENV.JSESSION);
            }
            if (!string.IsNullOrEmpty(json))
            {
                byte[] data = Encoding.UTF8.GetBytes(json);
                req.ContentLength = data.Length;
                using (Stream reqStream = req.GetRequestStream())
                {
                    reqStream.Write(data, 0, data.Length);
                    reqStream.Close();
                }
            }
            try
            {

            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            Stream stream = resp.GetResponseStream();
            //获取响应内容  
            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
            {
                result = reader.ReadToEnd();
            }
            return result;

            }
            catch (Exception)
            {
                MessageBox.Show("服务器连接超时，请稍后再试");
                return null;
            }
        }

        public static Result<T> Post<T>(string url, string json)
        {
            string stringResult = Post(url, json);
            if (stringResult==null)
            {
                stringResult = "";
            }
            Result<T> result = JsonConvert.DeserializeObject<Result<T>>(stringResult);
            return result;
        }
        public static Result<T> Post<T>(string uri, Dictionary<string, string> dic)
        {
            try
            {
                StringBuilder builder = new StringBuilder();
                int i = 0;
                foreach (var item in dic)
                {
                    if (i > 0)
                    {
                        builder.Append("&");
                    }
                    builder.AppendFormat("{0}={1}", item.Key, item.Value);
                    i++;
                }

                string result = string.Empty;
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(BaseUrl + uri);
                req.Method = "POST";
                req.UserAgent = "JNET/1.0";
                req.ContentType = "application/x-www-form-urlencoded";
                req.Headers.Add("x-requested-with", "XMLHttpRequest");
                req.Headers.Add("language", "zh_CN");
                //req.Headers.Add("account", HttpUtility.UrlEncode(LoginWindow.username, Encoding.GetEncoding("UTF-8")));
                //req.Headers.Add("password", HttpUtility.UrlEncode(LoginWindow.password, Encoding.GetEncoding("UTF-8")));
                req.Timeout = 120000;
                req.ProtocolVersion = new Version(1, 1);   //Http/1.1版本
                if (ENV.JSESSION != null)
                {
                    req.Headers.Add("Cookie", "JSESSIONID=" + ENV.JSESSION);
                }
                byte[] data = Encoding.UTF8.GetBytes(builder.ToString());
                req.ContentLength = data.Length;
                using (Stream reqStream = req.GetRequestStream())
                {
                    reqStream.Write(data, 0, data.Length);
                    reqStream.Close();
                }
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                Stream stream = resp.GetResponseStream();
                //获取响应内容  
                using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                {
                    result = reader.ReadToEnd();
                }
                Result<T> result1 = JsonConvert.DeserializeObject<Result<T>>(result);
                return result1;

            }
            catch (Exception)
            {
                //  MessageBox.Show(ex.Message);
                return null;
            }
        }
    }
    [DataContract]
    class SQLQueryObject
    {
        [DataMember]
        public string sql { get; set; }
        [DataMember]
        public object[] args { get; set; }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T">T为引用类型，则t=null有效，若T为数值类型，则t=0才有效</typeparam>
    public class Result<T>
    {
        [JsonProperty("status")]
        public string Status { get; set; }
        [JsonProperty("data")]
        public T Data { get; set; }
        [JsonProperty("message")]
        public string Message { get; set; }
    }
}
